fn leap_year(y: u16) -> bool {
    y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
}


fn maxd(y: u16, m: u8) -> u8 {
    if m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12 {
        31
    } else if m == 4 || m == 6 || m == 9 || m == 11 {
        30
    } else if leap_year(y) {
        29
    } else {
        28
    }
}

fn get_area(stage1: u8, stage2: u8, stage3: u8) -> Result<String, ()> {
    todo!()
}

fn check_id_card_1989(id_card_no: &str) -> Result<String, ()> {
    let id_arr: Vec<u8> = id_card_no.chars()
        .map(|c| to_digit_1999(c)).
        collect::<Result<Vec<_>, _>>()?;
    
    // check area
    let area = get_area(id_arr[0] * 10 + id_arr[1],
        id_arr[2] * 10 + id_arr[3],
        id_arr[4] * 10 + id_arr[5])?;

    // check date
    let y = 1900 + id_arr[6] as u16 * 10 + id_arr[7] as u16;
    let m = id_arr[8] * 10 + id_arr[9];
    let d = id_arr[10] * 10 + id_arr[11];
    if m < 1 || m > 12 || d < 1 || d > maxd(y, m) {
        return Err(());
    }
    let date = format!("{}年{}月{}日", y, m, d);

    // check gender
    let gender = match id_arr[14] & 1 {
        0 => "女",
        1 => "男",
        _ => panic!(),
    };
    let ret = format!("{},{},{}", gender, date, area);
    Ok(ret)
}

fn to_digit_1999(c: char) -> Result<u8, ()> {
    match c.to_digit(10) {
        Some(digit) => Ok(digit as u8),
        None => if c == 'X' {
            Ok(10)
        } else {
            Err(())
        }
    }
}
fn check_id_card_1999(id_card_no: &str) -> Result<String, ()> {
    let id_arr: Vec<u8> = id_card_no.chars()
        .map(|c| to_digit_1999(c)).
        collect::<Result<Vec<_>, _>>()?;
    
    // check chksum
    let checksum = id_arr.iter().rev()
    .fold((0, 1), |(s, p), v| {
        ((s + p * v) % 11, p * 2 % 11)
    }).0;
    if checksum != 1 {
        return Err(());
    }

    // check area
    let area = get_area(id_arr[0] * 10 + id_arr[1],
        id_arr[2] * 10 + id_arr[3],
        id_arr[4] * 10 + id_arr[5])?;

    // check date
    let y = id_arr[6] as u16 * 1000u16
        + id_arr[7] as u16 * 100 + id_arr[8] as u16 * 10 + id_arr[9] as u16;
    let m = id_arr[10] * 10 + id_arr[11];
    let d = id_arr[12] * 10 + id_arr[13];
    if m < 1 || m > 12 || d < 1 || d > maxd(y, m) {
        return Err(());
    }
    let date = format!("{}年{}月{}日", y, m, d);

    // check gender
    let gender = match id_arr[16] & 1 {
        0 => "女",
        1 => "男",
        _ => panic!(),
    };
    let ret = format!("{},{},{}", gender, date, area);
    Ok(ret)
}



fn check_id_card_inner(id_card_no: &str) -> Result<String, ()> {
    let len = id_card_no.len();
    if len == 18 {
        check_id_card_1999(id_card_no)
    } else if len == 15 {
        check_id_card_1989(id_card_no)
    } else {
        Err(())
    }
}

pub fn check_id_card(id_card_no: &str) -> String {
    if let Ok(info) = check_id_card_inner(id_card_no) {
        "身份证号码正确,".to_string() + &info
    } else {
        "身份证号码错误".to_string()
    }
}
